﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Ppt = Microsoft.Office.Interop.PowerPoint;

namespace ObjectModel.PowerPoint.Old
{
    /// <summary>
    /// Extends the event raising capabilities of a PowerPoint presentation.
    /// </summary>
    public class PresentationEvents
    {
        private Ppt.Application mApp = Globals.Application;
        //private Ppt.Presentation mPres;
        private List<ShapeInfo> mPrevSelectedShapes = new List<ShapeInfo>();
        private List<SlideInfo> mPrevSelectedSlides = new List<SlideInfo>();

        public delegate void ShapeChangedEventHandler(object sender, ShapeChangedEventArgs e);
        public delegate void SlideChangedEventHandler(object sender, SlideChangedEventArgs e);

        public event ShapeChangedEventHandler ShapeAdded;
        public event ShapeChangedEventHandler ShapeDeselected;
        public event ShapeChangedEventHandler ShapeDeleted;
        public event ShapeChangedEventHandler ShapeSelected;
        public event SlideChangedEventHandler SlideAdded;
        public event SlideChangedEventHandler SlideDeleted;
        public event SlideChangedEventHandler SlideActivated;
        public event Ppt.EApplication_WindowSelectionChangeEventHandler ShapeSelectionChanged;

        public SlideEventsManager SlideEvents { get; private set; }

        //public Ppt.Presentation Presentation
        //{
        //    get { return mPres; }
        //    set
        //    {
        //        mPres = value;

        //        mApp = mPres.Application;
        //        mApp.PresentationNewSlide += App_PresentationNewSlide;
        //        mApp.SlideSelectionChanged += App_SlideSelectionChanged;
        //        mApp.WindowSelectionChange += App_WindowSelectionChange;
        //    }
        //}

        //public PresentationEvents(Ppt.Presentation pres)
        //{
        //    Presentation = pres;

        //    SlideEvents = new SlideEventsManager(this);
        //}

        public PresentationEvents()
        {
            SlideEvents = new SlideEventsManager(this);
        }

        public void OnPresentationNewSlide(Ppt.Slide Sld)
        {
            // Ignore event if related to another presentation.
            //if (mApp.ActivePresentation.FullName != mPres.FullName) return;

            OnSlideAdded(new SlideInfo(Sld));

            foreach (Ppt.Shape sh in Sld.Shapes)
                OnShapeAdded(new ShapeInfo(sh));
        }

        public void OnSlideSelectionChanged(Ppt.SlideRange SldRange)
        {
            // Ignore event if related to another presentation.
            //if (mApp.ActivePresentation.FullName != mPres.FullName) return;

            IEnumerable<SlideInfo> selectedSlides = from Ppt.Slide s in SldRange
                                                    select new SlideInfo(s);

            IEnumerable<SlideInfo> deselectedSlides = mPrevSelectedSlides.Except(selectedSlides);
            foreach (SlideInfo sl in deselectedSlides)
            {
                // Check if previously selected slide still exists.
                try { int temp = sl.Slide.SlideID; }
                catch (COMException)
                {
                    // Slide has been deleted, raise slide and shape deleted events.
                    OnSlideDeleted(sl);

                    foreach (ShapeInfo sh in sl.Shapes)
                        OnShapeDeleted(sh);
                }
            }

            mPrevSelectedSlides = selectedSlides.ToList();

            OnSlideActivated(selectedSlides.First());
        }

        public void OnWindowSelectionChange(Ppt.Selection Sel)
        {
            // Ignore event if related to another presentation.
            //if (mApp.ActivePresentation.FullName != mPres.FullName) return;

            // Get currently selected slide if possible.
            Ppt.Slide currSlide = null;
            try { currSlide = Sel.SlideRange[1]; }
            catch (COMException) { }


            // If current selection is of a type that contains a shape or a selection of shapes.
            if (Sel.Type == Ppt.PpSelectionType.ppSelectionShapes || Sel.Type == Ppt.PpSelectionType.ppSelectionText)
            {
                OnShapeSelectionChanged(Sel);
                
                IEnumerable<ShapeInfo> selectedShapes = from Ppt.Shape s in Sel.ShapeRange
                                                        select new ShapeInfo(s);

                IEnumerable<ShapeInfo> deselectedShapes = mPrevSelectedShapes.Except(selectedShapes);
                foreach (ShapeInfo sh in deselectedShapes)
                    OnShapeDeselected(sh);

                IEnumerable<ShapeInfo> newlySelectedShapes = selectedShapes.Except(mPrevSelectedShapes);
                foreach (ShapeInfo sh in newlySelectedShapes)
                {
                    if (!PresentationManager.Shapes.ContainsKey(sh.UniqueId))
                        OnShapeAdded(sh);

                    OnShapeSelected(sh);
                }

                mPrevSelectedShapes = selectedShapes.ToList();
            }
            else
            {
                // Check if any shapes where in the previous selection.
                if (mPrevSelectedShapes.Count > 0)
                    foreach (ShapeInfo s in mPrevSelectedShapes)
                    {
                        // Check if previously selected shape still exists.
                        try
                        {
                            int temp = s.Shape.Id;
                            OnShapeDeselected(s); // Shape exists, raise deselection event.
                        }
                        catch (COMException)
                        {
                            if (currSlide != null)
                                // Shape has been deleted, raise shape removed event.
                                OnShapeDeleted(s);
                        }
                    }

                mPrevSelectedShapes.Clear();
            }
        }

        protected void OnShapeAdded(ShapeInfo shapeInfo)
        {
            if (ShapeAdded != null)
                ShapeAdded(this, new ShapeChangedEventArgs(shapeInfo));
        }

        protected void OnShapeDeselected(ShapeInfo shapeInfo)
        {
            if (ShapeDeselected != null)
                ShapeDeselected(this, new ShapeChangedEventArgs(shapeInfo));
        }

        protected void OnShapeDeleted(ShapeInfo shapeInfo)
        {
            if (ShapeDeleted != null)
                ShapeDeleted(this, new ShapeChangedEventArgs(shapeInfo));
        }

        protected void OnShapeSelected(ShapeInfo shapeInfo)
        {
            if (ShapeSelected != null)
                ShapeSelected(this, new ShapeChangedEventArgs(shapeInfo));
        }

        protected void OnShapeSelectionChanged(Ppt.Selection sel)
        {
            if (ShapeSelectionChanged != null)
                ShapeSelectionChanged(sel);
        }

        protected void OnSlideAdded(SlideInfo slideInfo)
        {
            if (SlideAdded != null)
                SlideAdded(this, new SlideChangedEventArgs(slideInfo));
        }

        protected void OnSlideDeleted(SlideInfo slideInfo)
        {
            if (SlideDeleted != null)
                SlideDeleted(this, new SlideChangedEventArgs(slideInfo));
        }

        protected void OnSlideActivated(SlideInfo slideInfo)
        {
            if (SlideActivated != null)
                SlideActivated(this, new SlideChangedEventArgs(slideInfo));
        }
    }
}
